import 'dart:developer' as developer;

import 'package:casdon/core/logger/log_file_output.dart';
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';

/// 日志工具类
class Log {
  static Logger? _instance;
  static bool _isInitialized = false;
  static bool _isProduction = false;

  static final List<LogOutput> _outputs = [ConsoleOutput()];

  static Future<void> init({
    required bool isProduction,
    required List<LogOutput> outputs,
  }) async {
    if (_isInitialized) return;

    _isProduction = isProduction;
    _outputs.addAll(outputs);

    for (final output in outputs) {
      if (output is LogFileOutput) {
        await output.init();
      }
    }

    _isInitialized = true;

    _instance = Logger(
      filter: _CustomLogFilter(isProduction: isProduction),
      printer: isProduction
          ? _ProductionPrinter()
          : PrettyPrinter(
              methodCount: 0,
              errorMethodCount: 8,
              lineLength: 120,
              colors: false,
              printEmojis: true,
              printTime: true,
            ),
      output: _MultiOutput(_outputs),
    );
  }

  static Future<void> ensureAllWritten() async {
    for (final output in _outputs) {
      if (output is LogFileOutput) {
        await output.ensureAllWritten();
      }
    }
  }

  static void v(
    dynamic message, {
    String tag = 'V',
    dynamic error,
    StackTrace? stackTrace,
  }) {
    _logToConsole('V', tag, message, error: error, stackTrace: stackTrace);
    _instance?.v("[$tag] $message", error, stackTrace);
  }

  static void d(
    dynamic message, {
    String tag = 'D',
    dynamic error,
    StackTrace? stackTrace,
  }) {
    _logToConsole('D', tag, message, error: error, stackTrace: stackTrace);
    _instance?.d("[$tag] $message", error, stackTrace);
  }

  static void i(
    dynamic message, {
    String tag = 'I',
    dynamic error,
    StackTrace? stackTrace,
  }) {
    _logToConsole('I', tag, message, error: error, stackTrace: stackTrace);
    _instance?.i("[$tag] $message", error, stackTrace);
  }

  static void w(
    dynamic message, {
    String tag = 'W',
    dynamic error,
    StackTrace? stackTrace,
  }) {
    _logToConsole('W', tag, message, error: error, stackTrace: stackTrace);
    _instance?.w("[$tag] $message", error, stackTrace);
  }

  static void e(
    dynamic message,
    Object error,
    StackTrace? stackTrace, {
    String tag = 'E',
  }) {
    _logToConsole('E', tag, message, error: error, stackTrace: stackTrace);
    _instance?.e("[E] $message", error, stackTrace);

    if (_isProduction) {
      _reportError(message, error, stackTrace);
    }
  }

  static Future<void> _reportError(
    dynamic message,
    dynamic error,
    StackTrace? stackTrace,
  ) async {
    try {
      // TODO: 上报错误到监控系统
    } catch (e) {
      _logToConsole('E', 'REPORT', 'Failed to report error', error: e);
      _instance?.e('[REPORT] Failed to report error', e);
    }
  }

  static void _logToConsole(
    String level,
    String tag,
    dynamic message, {
    dynamic error,
    StackTrace? stackTrace,
  }) {
    final String text = '[$level][$tag] $message';
    debugPrint(text);
  }
}

class _CustomLogFilter extends LogFilter {
  final bool isProduction;

  _CustomLogFilter({required this.isProduction});

  @override
  bool shouldLog(LogEvent event) {
    if (isProduction) {
      return event.level.index >= Level.warning.index;
    }
    return true;
  }
}

class _ProductionPrinter extends LogPrinter {
  @override
  List<String> log(LogEvent event) {
    return ['${event.time} [${event.level.name}] ${event.message}'];
  }
}

class _MultiOutput extends LogOutput {
  final List<LogOutput> outputs;

  _MultiOutput(this.outputs);

  @override
  void output(OutputEvent event) {
    for (final output in outputs) {
      try {
        output.output(event);
      } catch (e) {
        final message = 'Failed to output log: $e';
        debugPrint(message);
        print(message);
      }
    }
  }
}
